<?php

/**
 * @Author: king
 * @Date:   2019-05-04 23:04:04
 * @Last Modified by:   king
 * @Last Modified time: 2019-05-05 17:13:36
 */
namespace App\Http\Controllers\Api\v3;

use App\Http\Controllers\Api\BaseController;
use App\Http\Controllers\Api\v3\CheckOrdersController;
use App\Exceptions\ApiException;
use App\Tools\Orders as OrdersLib;
use App\Models\Api\Recode;
use App\Tools\Rectification;
use App\Models\Api\LanmeiFortune;
use App\Models\Api\LanmeiGoodsCommodityAttr;
use App\Models\Api\LanmeiOrder;
use App\Models\Api\LanmeiOrderGoods;
use Illuminate\Http\Request;

use Cache;
use DB;
class LanmeiOrdersController extends BaseController
{
 /**
     * 订单重构,统一下单入口
     * @return array|\think\response\Json
     * @throws ApiException
     */
    private function pay_order(Request $request)
    {
        $param = $request->all();

        switch ($param['gid'])
        {
            case 1:
                $scene = 'v10_pay_rec';
                break;
            case 2:
                $scene = 'v10_pay_fortune';
                break;
            case 3:
                $scene = 'v10_pay_map';
                break;
            case 4:
                $scene = 'v10_pay_video';
                break;
            default :
                return show(config('code.error'), '订单类型未知');
        }
        //验证订单下单参数
        $validate = \App\Tools\ValidatesLanmeiOrder();
        if ($validate->scene($scene)->check($param) !== true)
        {
            return show(config('code.error'), json_encode($validate->getError(), true));
        }

        $trade_type = $param['trade_type'];//支付方式
        $gid = $param['gid'] ?? 0;//商品id
        $gctid = $param['gctid'] ?? 0;//货品属性类型
        $gctids = $param['gctids'] ?? '';//货品属性类型,多个
        $rid = $param['rid'] ?? 0;//档案id
        $rids = $param['rids'] ?? '';//多个档案id
        $rids = explode(',', $rids);

        $rec_start_time = $param['rec_start_time'] ?? '';//生时矫正开始时间
        $rec_end_time = $param['rec_end_time'] ?? '';//生时矫正结束时间
        $events = $param['events'] ?? '';//生时矫正事件,json类型
        $fortune_type = $param['fortune_type'] ?? 0;//运势类型1=>日运,2=>月运,3=>年运
        $map_type = $param['map_type'] ?? 0;//地图类型1=>打包,2=>不打包
        $fortune_time = $param['fortune_time'] ?? '';//开通运势时间
        $openid = $param['openid'] ?? '';//网页支付所需参数
        $callback_url = $param['callback_url'] ?? '';//网页支付所需参数
        $uid = $request->uid;
        $now_time = time();

        $LanmeiOrder = new LanmeiOrder();
        $LanmeiOrderGoods = new LanmeiOrderGoods();

        //获取下单的价格
        switch ($gid)
        {
            case 1:
                $pay_des = '准吖 - 生时校正';
                // 生成唯一订单号  011806192149570386
                $out_trade_no = str_pad(1, 2, '0', STR_PAD_LEFT) . date('YmdHis') . str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
                $price = $this->pay_rec(['gctid' => $gctid, 'order_type' => $gid]);
                break;
            case 2:
                $pay_des = '准吖 - 运势';
                // 生成唯一订单号  021806192149570386
                $out_trade_no = str_pad(2, 2, '0', STR_PAD_LEFT) . date('YmdHis') . str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
                $price = $this->pay_fortune(['gctid' => $gctid, 'rids' => $rids, 'fortune_time' => $fortune_time, 'fortune_type' => $fortune_type, 'order_type' => $gid]);
                break;
            case 3:
                $pay_des = '准吖 - 占星地图';
                // 生成唯一订单号  031806192149570386
                $out_trade_no = str_pad(3, 2, '0', STR_PAD_LEFT) . date('YmdHis') . str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
                $price = $this->pay_map(['gctids' => $gctids, 'rid' => $rid, 'type' => $map_type, 'order_type' => $gid]);
                break;
            case 4:
                $pay_des = '准吖 - 占星视频';
                // 生成唯一订单号  041806192149570386
                $out_trade_no = str_pad(4, 2, '0', STR_PAD_LEFT) . date('YmdHis') . str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
                $price = $this->pay_video(['gctid' => $gctid, 'order_type' => $gid]);
                break;
            default :
                return show(config('code.error'), '下单商品信息有误,请重新下单');
        }
        // VIP 价格全部 0.01元
        $vipLevel = getVips($uid);
        // 获取当前用户的档案id
        $selfId = (new Recode())->getSelfRecode(['uid' => $uid]);

        if ($vipLevel === 1 || ($vipLevel > 1 && ($rid == $selfId['id'] || (count($rids) == 1 && $rids[0] == $selfId['id']))))
        {
            $price = 0.01;
        }

        //开启事务
        DB::startTrans();
        try
        {
            $insert = [
                'uid' => $uid,
                'order_type' => $gid,
                'order_id' => $out_trade_no,
                'pay_type_id' => $trade_type,
                'total_amount' => $price,
                'create_time' => $now_time,
                'status' => 0,
                'pay_status' => 0,
                'expire_time' => time() + 86400
            ];
            $oid = $LanmeiOrder->saveOrder($insert);

            $order_good = [];
            $save_rectification = true;
            $save_fortune = true;
            switch ($gid)
            {
                case 1:
                    $save_rectification = $this->saveRectification(['oid' => $oid, 'rid' => $rid, 'start_time' => $rec_start_time, 'end_time' => $rec_end_time, 'events' => $events]);
                    break;
                case 2:
                    foreach ($rids as $rid)
                    {
                        $order_good[] = [
                            'oid' => $oid,
                            'gctid' => $gctid,
                            'rid' => $rid
                        ];
                    }
                    $save_fortune = $this->saveFortune(['oid' => $oid, 'fortune_type' => $fortune_type, 'fortune_time' => $fortune_time]);
                    break;
                case 3:
                    foreach ($gctids as $gctid)
                    {
                        $order_good[] = [
                            'oid' => $oid,
                            'gctid' => $gctid,
                            'rid' => $rid
                        ];
                    }
                    break;
                default :
                    $order_good[] = [
                        'oid' => $oid,
                        'gctid' => $gctid,
                        'rid' => $rid
                    ];
                    break;
            }

            $order_good_status = $LanmeiOrderGoods->saveOrder($order_good);

            if ($oid && $order_good_status && $save_fortune && $save_rectification)
            {
                DB::commit();
            } else
            {
                DB::rollback();
            }
        }
        catch (\Exception $e)
        {
            DB::rollback();

            return show(config('code.error'), '下单失败,请稍候重试');
        }

        if ($save_rectification == 1)
        {
            return show(config('code.success'), '有效事件太少，可能导致校正不准确，要继续提交吗');
        }

        //支付订单
        $arr = (new OrdersLib())->unifyPayOrder(['trade_type' => $trade_type, 'total_amount' => $price, 'pay_des' => $pay_des, 'order_id' => $out_trade_no, 'openid' => $openid, 'callback_url' => $callback_url]);

        return $arr;
    }

    /**
     * 生时矫正下单,获取商品信息
     * @param array $map
     * @return float|int|mixed|\think\response\Json
     */
    public function pay_rec($map = [])
    {
        if (Cache::get($request->uid . ':pay:rec')) return show(config('code.error'), '请勿频繁操作');
        Cache::set($request->uid . ':pay:rec', time(), 5);
        // TODO 检测档案时间是否合适,不可为超出现在的时间
        $price = $this->getGoods(['gctid' => $map['gctid']]);
        return $price;
    }

    /**
     * 运势下单,获取商品信息
     * @param array $map
     * @return float|int|mixed|\think\response\Json
     * @throws ApiException
     * @throws \Exception
     */
    public function pay_fortune($map = [])
    {
        if (Cache::get($request->uid . ':pay:fortune')) return show(config('code.error'), '请勿频繁操作');
        Cache::set($request->uid . ':pay:fortune', time(), 5);

        $gctid = $map['gctid'];
        $rids = $map['rids'];
        $fortune_time = $map['fortune_time'];
        $fortune_type = $map['fortune_type'];
        $order_type = $map['order_type'];
        $uid = $request->uid;

        $CheckOrders = new CheckOrdersController();
        $LanmeiGoodsAttr = new LanmeiGoodsCommodityAttr();
        foreach ($rids as $rid)
        {
            //判断当前档案当天时间是否有已支付的订单
            $CheckOrders->check_prepaid_fortune(['rid' => $rid, 'time' => $fortune_time, 'fortune_type' => $fortune_type, 'uid' => $uid, 'order_type' => $order_type]);
            //判断当前档案当天时间是否有未支付的订单
            $CheckOrders->check_unpaid_fortune(['rid' => $rid, 'time' => $fortune_time, 'fortune_type' => $fortune_type, 'uid' => $uid, 'order_type' => $order_type]);
        }

        //判断购买的时间是否超出服务器预定的时间
        //获取当前解锁的开始时间和结束时间
        $date = $fortune_time;
        switch ($fortune_type)
        {
//            case 1:
//                $GoodsInfo = $LanmeiGoodsAttr->getCommodityInfo(['id'=>$gctid]);
//                $start_time = $dt->format('U');//获取时间戳
//
//                break;
            case 2:
                $date = $fortune_time . '-01';
                $month_start_time = config('fortune.fortune_time_range')['month']['start'] . '-1';
                $month_end_time = config('fortune.fortune_time_range')['month']['end'] . '-12';
                $fortune_start_time = strtotime($month_start_time);
                $fortune_end_time = strtotime($month_end_time);

                break;
            case 3:
                $date = $fortune_time . '-01-01';
                $year_start_time = config('fortune.fortune_time_range')['year']['start'] . '-1-1';
                $year_end_time = config('fortune.fortune_time_range')['year']['end'] . '-12-31';
                $fortune_start_time = strtotime($year_start_time);
                $fortune_end_time = strtotime($year_end_time);

                break;
        }

        $dt = new \DateTime($date);
        $GoodsInfo = $LanmeiGoodsAttr->getCommodityInfo(['id' => $gctid]);
        $start_time = $dt->format('U');//获取时间戳

        $dt->modify($GoodsInfo['gattr']);//加一天(只能是字符串类型)
        $dt->modify('-1 day');//加一天(只能是字符串类型)
        $end_time = $dt->format('U');//获取时间戳

        //购买时间超出2018-2037提示用户不可购买
        if (isset($fortune_start_time) && isset($fortune_end_time) && isset($start_time) && isset($end_time) && $fortune_start_time && $fortune_end_time && $start_time && $end_time)
        {
            if ($start_time < $fortune_start_time || $end_time > $fortune_end_time)
            {
                throw new ApiException('您购买的运势时间超出时间范围，请重新确认。', 200, config('code.error'));
            }
        }
        //获取解锁的商品价格
        $price = $this->getGoods(['gctid' => $gctid]);

        $price = $price * count($rids);

        return $price;

    }

    /**
     * 占星地图下单,获取商品信息
     * @param array $map
     * @return float|int|\think\response\Json
     * @throws ApiException
     */
    public function pay_map($map = [])
    {
        if (Cache::get($request->uid . ':pay:map')) return show(config('code.error'), '请勿频繁操作');
        Cache::set($request->uid . ':pay:map', time(), 5);
        $rid = $map['rid'];
        $gctids = $map['gctids'];
        $type = $map['type'];
        $uid = $request->uid;
        $order_type = $map['order_type'];

        $gctids = explode(',', $gctids);
        $CheckOrder = new CheckOrdersController();
        foreach ($gctids as $gctid)
        {
            //判断当前档案是否解锁当前命格线
            $CheckOrder->check_prepaid_map(['gctid' => $gctid, 'rid' => $rid, 'uid' => $uid, 'order_type' => $order_type]);
            //判断当前档案当前命格线是否有未支付订单
            $CheckOrder->check_unpaid_map(['gctid' => $gctid, 'rid' => $rid, 'uid' => $uid, 'order_type' => $order_type]);

            //获取解锁的商品价格
            $price = $this->getManyGoods(['gctids' => $gctids]);
        }

        //获取打包解锁的商品价格
        if ($type == 1)
        {
            $price = 99;
        }

        return $price;
    }

    /**
     * 占星视频下单,获取商品信息
     * @param array $map
     * @return \think\response\Json
     * @throws ApiException
     */
    public function pay_video($map = [])
    {
        if (Cache::get($request->uid . ':pay:video')) return show(config('code.error'), '请勿频繁操作');
        Cache::set($request->uid . ':pay:video', time(), 5);
        $uid = $request->uid;
        $gctid = $map['gctid'];
        $order_type = $map['order_type'];
        $CheckOrder = new CheckOrdersController();
        //判断当前用户是否解锁当前课程
        $CheckOrder->check_prepaid_video(['uid' => $uid, 'gctid' => $gctid, 'order_type' => $order_type]);
        //判断当前用户当前课程是否有未支付的订单
        $CheckOrder->check_unpaid_video(['uid' => $uid, 'gctid' => $gctid, 'order_type' => $order_type]);
        //获取解锁的商品价格
        $price = $this->getGoods(['gctid' => $map['gctid']]);
        return $price;
    }

    /**
     * 获取下单的商品价格
     * @param array $map
     * @return float|int|mixed
     */
    public function getGoods($map = [])
    {
        $gctid = $map['gctid'];
        $LanmeiGoodsAttr = new  LanmeiGoodsCommodityAttr();
        $GoodsInfo = $LanmeiGoodsAttr->getCommodityInfo(['id' => $gctid]);
        if ($GoodsInfo === false)
        {
            return show(config('code.error'), $LanmeiGoodsAttr->getError());
        }
        if (!$GoodsInfo['type_id'])
        {
            $price = $GoodsInfo['now_price'];
        } else
        {
            $discount = json_decode($GoodsInfo['aattr'], true);
            $time = time();
            if ($GoodsInfo['start_time'] <= $time && $time <= $GoodsInfo['end_time'])
            {
                $price = $GoodsInfo['now_price'] * $discount['discount'];
            }
        }
        return $price;
    }

    /**
     * 获取下单的多个商品价格
     * @param array $map
     * @return float|int|mixed
     */
    public function getManyGoods($map = [])
    {
        $gctids = $map['gctids'];
        $LanmeiGoodsAttr = new  LanmeiGoodsCommodityAttr();
        $price = 0;
        foreach ($gctids as $gctid)
        {
            $GoodsInfo = $LanmeiGoodsAttr->getCommodityInfo(['id' => $gctid]);
            if ($GoodsInfo === false)
            {
                return show(config('code.error'), $LanmeiGoodsAttr->getError());
            }
            if (!$GoodsInfo['type_id'])
            {
                $price += $GoodsInfo['now_price'];
            } else
            {
                $discount = json_decode($GoodsInfo['aattr'], true);
                $time = time();
                if ($GoodsInfo['start_time'] <= $time && $time <= $GoodsInfo['end_time'])
                {
                    $price += $GoodsInfo['now_price'] * $discount['discount'];
                }
            }
        }
        return $price;
    }

    /**
     * 保存生时矫正历史记录
     * @param array $map
     * @return array|bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function saveRectification($map = [])
    {
        //订单id
        $oid = $map['oid'];
        // 档案id
        $rid = $map['rid'];
        // 校正开始时间
        $start_time = strtotime($map['start_time']);
        // 校正结束时间
        $end_time = strtotime($map['end_time']);
        if ($start_time == $end_time) return show(config('code.error'), '矫正时间不能相同', []);
        if (($start_time - $end_time) > 0) return show(config('code.error'), '开始时间不能大于结束时间', []);
        if (($start_time - $end_time) < 7200 && 7200 == ($start_time - $end_time)) return show(config('code.error'), '时间不可超过两小时', []);
//        if (abs(date('h',$start_time) - date('h',$end_time)) > 2) return show(config('code.error'),'时间不可超过两小时',[]);
        // 生时校正事件json
        $events = $map['events'];
        $ev = json_decode($events, true);
        foreach ($ev as $k => $v)
        {
            if (strtotime($v['time']) > time()) return show(config('code.error'), '事件时间不能大于当前时间', []);

            $ev[$k]['time'] = strtotime($v['time']);
        }
        $uid = $request->uid;
        // 检测传参
        if (!$uid || !$rid || !$events || empty($events))
        {
            return show(config('code.error'), '参数错误', [], 400);
        }
        // 时间范围超出两小时 或者结束时间小于开始时间
        if (($end_time - $start_time) > 7200 || ($end_time - $start_time) < 0)
        {
            return show(config('code.error'), '参数错误', [], 400);
        }
        $field = 'type,year,month,day,hour,minute,timezone,long_deg,long_min,ew,lat_deg,lat_min,ns,is_summer';
        // 获取该档案下的出生信息 以便进行矫正
        $recode = model('recode')->field($field)
            ->where(['id' => $rid, 'uid' => $uid, 'isself' => 1])->find();

        if ($recode === null)
        {
            return show(config('code.error'), '当前仅限校正自己的档案', [], 400);
        }
        // 矫正范围的中点时间
        $birth_time_mid = ($start_time + $end_time) / 2;

        // 有效事件判断
        $event_array = (new Rectification())->getValidEvents($ev, $birth_time_mid, $recode);

        // 初始化有效事件数量
        $vaild_num = 0;
        // 有效事件++
        foreach ($event_array as $ea) if ($ea['status'] == 1) $vaild_num++;

        $gid = 1;// 生时校正

        $goods = model('Goods')->field('id,name,or_prize,now_prize')->where('status', config('code.status_normal'))->find($gid);

        if (!$goods || empty($goods))
        {
            return show(config('code.error'), '商品不存在');
        }

        $status = 0;

        if ($vaild_num < 1)
        {
            return $status;
        }

        // 入库  付款后 加入计算队列
        try
        {
            $insert_data = [
                'oid' => $oid,
                'status' => 0,
                'rec_status' => 0,
                'start_time' => $start_time,
                'end_time' => $end_time,
                'creat_time' => time()
            ];
            $rectification = new LanmeiRectification();
            // 存入生时校正表
            $rectification->allowField(true)->save($insert_data);

            // 存入生时校正事件表
            $rectification->events()->saveAll($event_array);

        }
        catch (\Exception $e)
        {
            return false;
        }


        if ($vaild_num < 3)
        {
            $status = 1;

            return $status;
        }

        $status = 2;

        return $status;
    }

    /**
     * 保存运势记录
     * @param array $map
     * @return bool|\think\response\Json
     */
    public function saveFortune($map = [])
    {
        $insert = [
            'oid' => $map['oid'],
            'fortune_status' => 0,
            'type' => $map['fortune_type'],
            'time' => strtotime($map['fortune_time']),
            'create_time' => time()
        ];

        $LanmeiFortune = new LanmeiFortune();

        try
        {
            $LanmeiFortune->insert($insert);
        }
        catch (\Exception $e)
        {
            return show(config('code.error'), '运势数据保存失败');
        }

        return true;
    }

}
